<?php


namespace App\Services;


use App\Models\Role;
use App\Models\User;
use App\Utils\Code;
use App\Utils\Regex;
use App\Utils\Tools;
use App\Utils\Tree;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

class UserService extends BaseService
{

    /**
     * 用户登录
     * @param array $params
     */
    public function login(array $params) {
        $user = User::where('phone', $params['phone'])->with(['role'])->first();
        if (! $user || ! Hash::check($params['password'], $user->password)) {
            throw new \Exception('密码错误', Code::PARAMETER_ERROR);
        }
        $user->token = $user->createToken('account')->plainTextToken;
        return $user;
    }

    /**
     * 退出登陆
     * @param Request $request
     * @return bool
     * @throws \Exception
     */
    public function logout() {
        try {
            try {
                if (!Auth::id()){
                    throw new \Exception('你当前身份并没有登陆', Code::INCOMPLETE_DATA);
                }
            } catch (\Exception $exception) {
                Code::log($exception->getMessage(), $exception->getCode());
                return true;
            }
            return $this::$user->tokens()->delete();
        } catch (\Exception $exception) {
            throw new \Exception($exception->getMessage(), Code::LACK_OF_CONDITIONS);
        }
    }

    /**
     * 创建数据
     * @param array $params
     * @param bool $isAdmin
     * @return mixed
     * @throws \Throwable
     */
    public function store(array $params = []){
        if (!$this->checkParams($params)){
            throw new \Exception('请求参数验证不通过', Code::PARAMETER_ERROR);
        }
        return DB::transaction(function () use ($params){
            $model = new User();
            $model->phone = isset($params['phone']) ? $params['phone'] : null;
            $model->name = isset($params['name']) ? $params['name'] : null;
            $model->avatar = isset($params['avatar']) ? $params['avatar'] : null;
            $model->password = !empty($params['password']) ? Hash::make($params['password']) : Hash::make('a123456');
            if ($this::$admin){
                if (isset($params['is_admin'])){
                    $model->is_admin = (int)$params['is_admin'];
                }
                if (isset($params['role_id'])){
                    if ($params['role_id']) {
                        $model->role_id = ((new RoleService())->show($params['role_id']))->id;
                    } else {
                        $model->role_id = null;
                    }
                }
                if (isset($params['status'])){
                    $model->status = (int)$params['status'];
                }
            }
            return $model->save();
        });
    }

    /**
     * 详细数据
     * @param null $id
     * @param bool $simple
     * @param bool $abnormal
     * @param false $isToken
     * @param string $mode
     * @param string $session
     * @param null $check
     * @param null $mark
     * @return Builder|\Illuminate\Database\Eloquent\Model|object|JWTSubject|null
     * @throws \Exception
     */
    public function show($id, $abnormal = true){
        $model = User::where('id', $id ? (int)$id : Auth::id())->with(['role'])->first();
        if (!$model && $abnormal) {
            throw new \Exception('不存在的用户ID主键', Code::EMPTY_DATA);
        }
        return $model;
    }

    /**
     * 更新数据
     * @param array $params
     * @param null $id
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
     * @throws \Exception
     */
    public function update($id, array $params){
        if (isset($params['mode']) && $params['mode'] == 'change_password') {
           return $this->changePassword($id, $params);
        }
        if (!$this->checkParams($params, $id, true)){
            throw new \Exception('请求参数验证不通过', Code::PARAMETER_ERROR);
        }
        return DB::transaction(function () use ($id, $params){
            $model = $this->show($id);
            $model->phone = isset($params['phone']) ? $params['phone'] : null;
            $model->name = isset($params['name']) ? $params['name'] : null;
            $model->avatar = isset($params['avatar']) ? $params['avatar'] : null;
           
            if (!empty($params['password'])) {
                $model->password = Hash::make($params['password']);
            }
            if ($this::$admin){
                if (isset($params['is_admin'])){
                    $model->is_admin = (int)$params['is_admin'];
                }
                if (isset($params['role_id'])){
                    if ($params['role_id']) {
                        $model->role_id = ((new RoleService())->show($params['role_id']))->id;
                    } else {
                        $model->role_id = null;
                    }
                }
                if (isset($params['status'])){
                    $model->status = (int)$params['status'];
                }
            }
            $model->save();
            return $this->show($id);
        });
    }
    
    public function changePassword($id, array $params){
        if (!$this->checkChangePasswordParams($params, $id, true)){
            throw new \Exception('请求参数验证不通过', Code::PARAMETER_ERROR);
        }
        return DB::transaction(function () use ($id, $params){
            $model = $this->show($id);
            if (!Hash::check($params['password'], $model->password)) {
                throw new \Exception('密码错误', Code::PARAMETER_ERROR);
            }
            if ($params['new_password'] !== $params['new_password_confirm']) {
                throw new \Exception('密码输入不一致', Code::PARAMETER_ERROR);
            }
            $model->password = Hash::make($params['new_password']);
            return $model->save();
        });
    }

    /**
     * 用户列表
     * @param array $params
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     */
    public function index(array $params = []){
        $model = User::with(['role', 'ips', 'accounts']);
        if (isset($params['phone']) && $params['phone']){
            $model = $model->where('phone', $params['phone']);
        }
        if (isset($params['user_id']) && is_numeric($params['user_id'])) {
            $model = $model->where('user_id', $params['user_id']);
        }
        if (isset($params['name']) && $params['name']){
            $model = $model->where('name', 'like', '%'.$params['name'].'%');
        }
        if (isset($params['role_id']) && is_numeric($params['role_id'])){
            $model = $model->where('role_id', (int)$params['role_id']);
        }
        return $model->orderBy('created_at', 'desc')
            ->paginate(isset($params['per_page']) ? (int)$params['per_page'] : 15);
    }

    /**
     * 删除数据
     * @param $id
     * @return bool|mixed|null
     * @throws \Exception
     */
    public function destroy($id) {
        $info = $this->show($id);
        if (!$this::$admin){
            throw new \Exception('你没有删除用户的权限', Code::LACK_OF_CONDITIONS);
        }
        return $info->delete();
    }

    /**
     * 用户菜单
     * @param array $params
     * @return array
     * @throws \Exception
     */
    public function menus(array $params = []) {
        $model = Role::where('id', $this::$user->role_id)->with([
            'menus' => function ($query) {
                $query->orderBy('sort', 'asc');
            }
        ])->first();
        $lists = [];
        foreach($model->menus as $menu) {
            $list = $menu->toArray();
            if (!empty($list['meta']['permission'])) {
                $list['meta']['permission'] = $list['pivot']['permission'];
            }
            $lists[] = $list;
        }
        if (isset($params['format']) && $params['format'] == 'list'){
            $lists = Tree::instance()->treeFormat($lists, 'children', null);
        } else {
            $lists = Tree::instance()->toTree($lists, 'id');
        }
        return $lists;
    }

    /**
     * 验证参数
     * @param array $params
     * @param null $id
     * @param bool $isUpdate
     * @return array
     * @throws \Exception
     */
    private function checkParams(array $params, $id = null, $isUpdate = false){
        $rules = [
            'is_admin' => 'bail|in:0,1',
            'phone' => ['bail', 'nullable', 'regex:'.Regex::regex['phone'], Rule::unique('users')->ignore($id, 'user_id')],
            'password' => ['bail', 'nullable', 'regex:' . Regex::regex['password']],
            'role_id' => ['bail', 'nullable', 'integer'],
            'status' => 'bail|in:0,1'
        ];
        if ($isUpdate){
            // 删除必选条件
            unset($rules['phone']);
            foreach ($rules as $field => &$rule){
                if (isset($rule[1]) && $rule[1] == 'required') {
                    $rule[1] = 'nullable';
                }
            }
        }
        $validator = Validator::make($params, $rules, [
            'password.regex' => '有效的密码为6-18位之间的字母数字组合'
        ], [
            'is_admin' => '用户身份',
            'phone' => '手机号码',
            'password' => '登陆密码',
            'role_id' => '权限分组',
            'status' => '用户状态'
        ]);
        if ($validator->fails()) {
            throw new \Exception($validator->errors()->first(), Code::PARAMETER_ERROR);
        }
        return $params;
    }

    /**
     * 验证参数
     * @param array $params
     * @param null $id
     * @param bool $isUpdate
     * @return array
     * @throws \Exception
     */
    private function checkChangePasswordParams(array $params){
        $rules = [
            'password' => ['bail', 'required', 'regex:'.Regex::regex['password']],
            'new_password' => ['bail', 'required', 'regex:'.Regex::regex['password']],
            'new_password_confirm' => ['bail', 'required', 'regex:'.Regex::regex['password']]
        ];
       
        $validator = Validator::make($params, $rules, [
            'password.regex' => '有效的密码为6-18位之间的字母数字组合',
            'new_password.regex' => '有效的密码为6-18位之间的字母数字组合',
            'new_password_confirm.regex' => '有效的密码为6-18位之间的字母数字组合'
        ], [
            'password' => '旧密码',
            'new_password' => '新密码',
            'new_password_confirm' => '新密码确认'
        ]);
        if ($validator->fails()) {
            throw new \Exception($validator->errors()->first(), Code::PARAMETER_ERROR);
        }
        return $params;
    }
}
